<template>
  <div v-loading="loading" class="pub-upload">
    <el-upload
      ref="fileUpload"
      :class="{ hide: hideUpload }"
      action="/api/basic/files"
      :headers="headers"
      :on-success="uploadSuccess"
      list-type="picture-card"
      :file-list="state.fileList"
      :auto-upload="false"
      :on-change="selectChange"
      :disabled="disabled"
      :http-request="httpRequest"
    >
      <el-icon>
        <Plus />
      </el-icon>
      <template #file="{ file }">
        <div>
          <el-image
            v-if="file.fileType == 'img'"
            style="width: 146px; height: 146px"
            :src="file.fullUrl"
            fit="fill"
          />
          <div v-if="file.fileType == 'video'">
            <video width="146" height="146" autoplay>
              <source :src="file.fullUrl" type="video/mp4" />
              <!-- <source src="movie.ogg" type="video/ogg" /> -->
              您的浏览器不支持 HTML5 video 标签。
            </video>
          </div>
          <div
            v-if="
              file.fileType &&
              file.fileType != 'img' &&
              file.fileType != 'video'
            "
          >
            <img :src="getImageUrl(file.fileType)" class="file-type-icon" />
            <div class="file-name">{{ file.fileName }}</div>
          </div>

          <span class="el-upload-list__item-actions">
            <span
              v-if="file.fileType == 'img'"
              class="el-upload-list__item-preview"
              @click="viewImg(file)"
            >
              <el-icon>
                <ZoomIn />
              </el-icon>
            </span>
            <span v-else-if="file.fileType == 'video'" @click="videoPlay(file)">
              <i class="el-icon-video-play" />
              <el-icon>
                <VideoPlay />
              </el-icon>
            </span>
            <span
              v-else
              class="el-upload-list__item-delete"
              @click="download(file)"
            >
              <el-icon>
                <Bottom />
              </el-icon>
            </span>
            <span
              v-if="!disabled"
              class="el-upload-list__item-delete"
              @click="delFile(file)"
            >
              <el-icon>
                <Delete />
              </el-icon>
            </span>
          </span>
        </div>
      </template>
    </el-upload>
    <pub-dialog title="裁剪" v-model="showCropper" width="1000px">
      <vueCropper
        class="crop-box"
        ref="cropper"
        :img="options.img"
        :autoCrop="options.autoCrop"
        :fixedBox="options.fixedBox"
        :canMoveBox="options.canMoveBox"
        :autoCropWidth="options.autoCropWidth"
        :autoCropHeight="options.autoCropHeight"
        :centerBox="options.centerBox"
        :fixed="options.fixed"
        :fixedNumber="options.fixedNumber"
        :canMove="options.canMove"
        :canScale="options.canScale"
      ></vueCropper>
      <div class="cropper-bottom">
        <el-button @click="cancel">取 消</el-button>
        <el-button type="primary" @click="getCrop">确 定</el-button>
      </div>
    </pub-dialog>
    <span v-if="empty && disabled" class="empty-content">{{ emptyText }}</span>
    <el-image-viewer
      v-if="showViewer"
      @close="closeViewer"
      :url-list="selectImg"
    />
    <pub-dialog
      v-if="videoDialog"
      title="播放"
      v-model:visible="videoDialog"
      width="340px"
    >
      <video autoplay width="300px" controls>
        <source
          src="http://192.168.45.42:8989/group1/M00/00/7E/wKgtKmJ2G-CEJXP7AAAAAFXw7TM992.mp4"
          type="video/mp4"
        />
        <!-- <source src="movie.ogg" type="video/ogg" /> -->
        您的浏览器不支持 HTML5 video 标签。
      </video>
    </pub-dialog>
    <el-input
      v-model="props.bizId"
      style="display: none"
      maxlength="50"
    ></el-input>
  </div>
</template>

<script setup>
import { upload_file } from '@/api/system'
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import {
  Delete,
  ZoomIn,
  Bottom,
  Plus,
  VideoPlay
} from '@element-plus/icons-vue'
import { changeSize } from '@/utils'
import { useUserStore } from '@/pinia/modules/user'
import { ElMessage } from 'element-plus'
const emit = defineEmits(['update:bizId', 'success', 'videoInfos'])
const ALL_TYPE = [
  'png',
  'jpg',
  'jpeg',
  'bmp',
  'gif',
  'jfif',
  'txt',
  'xlsx',
  'xls',
  'doc',
  'docx',
  'pdf',
  'ppt',
  'pptx',
  'zip',
  'mp4',
  'webp',
  'pdf',
  'pdfx'
]
const IMG = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'jfif', 'webp']
const EXCEL = ['xlsx', 'xls']
const WORD = ['doc', 'docx']
const PPT = ['ppt', 'pptx']
const VIDEO = ['mp4']
const PDF = ['pdf', 'pdfx']
const userStore = useUserStore()
const props = defineProps({
  validateField: {
    type: Function,
    default: null
  },
  disabled: {
    type: Boolean,
    default() {
      return false
    }
  },
  emptyText: {
    type: String,
    default: '暂无附件'
  },
  limit: {
    type: String,
    default: '10'
  },
  bizId: {
    type: String,
    default: ''
  },
  bizType: {
    type: String,
    default: ''
  },
  fileSize: {
    type: Number,
    default: 8
  },
  allowUploadTypes: {
    type: Array,
    default: () => ['jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf']
  }
})

const fileUrl = ref('')
const videoDialog = ref(false)
const tempFiles = ref([])
const loading = ref(false)
const headers = ref({
  Authorization: userStore.token
})
const selectImg = ref([])
const showViewer = ref(false)
const hideUpload = ref(false)
const empty = ref(false)
const baseUrl = ref('/api/service/oss/aliyun/upload') // 上传的路径
const cropper = ref()
const showCropper = ref(false)
const state = reactive({
  file: null,
  fileList: [],
  fileList_local: []
})
const options = reactive({
  img: '', // 原图文件
  autoCrop: true, // 默认生成截图框
  fixedBox: false, // 固定截图框大小
  canMoveBox: true, // 截图框可以拖动
  // autoCropWidth: 271, // 截图框宽度
  // autoCropHeight: 182, // 截图框高度
  fixed: true, // 截图框宽高固定比例
  fixedNumber: [1.49, 1], // 截图框的宽高比例
  centerBox: true, // 截图框被限制在图片里面
  canMove: false, // 上传图片不允许拖动
  canScale: false // 上传图片不允许滚轮缩放
})
const fileUpload = ref()
const getImageUrl = name => {
  return new URL(`../../assets/img/file-icon/${name}.png`, import.meta.url).href
}

const lookImg = item => {
  // this.dialogImageUrl = item.url;
  // this.dialogVisible_lookImg = true;
}

const videoPlay = file => {
  videoDialog.value = true
}

const handleRemove = file => {
  console.log(file)
  // 展示层删除
  state.fileList_local.splice(
    state.fileList_local.findIndex(
      item => item.imgId === (file.imgId || file.response.data.id)
    ),
    1
  )

  state.fileList = state.fileList.filter(item => item.imgId != file.imgId)
}

const download = file => {
  window.open(file.fullUrl)
}

const init = async fileUrl => {
  // 获取已有图片或文件并处理
  loading.value = true
  const res = await getAllFiles(`${fileUrl}/metadatas/by_ids/${props.bizId}`)
  if (!res.data || res.data.length === 0) {
    empty.value = true
    loading.value = false
    if (props.disabled) {
      hideUpload.value = true
    }
    return
  }
  let notImgFiles = []
  let imgFilesInfo = []
  let imgFiles = res.data.filter(item => {
    if (calFileType(item.name) !== 'img') {
      notImgFiles.push(item)
    }
    return calFileType(item.name) === 'img'
  })

  if (notImgFiles && notImgFiles.length > 0) {
    notImgFiles = notImgFiles.map(item => {
      return {
        imgId: item.id,
        fullUrl: fileUrl + '/download/' + item.id,
        bigUrl: fileUrl + '/download/' + item.id,
        url: fileUrl + '/download/' + item.id,
        fileType: calFileType(item.name),
        fileName: item.name
      }
    })
  }

  if (imgFiles && imgFiles.length > 0) {
    let tempFilesArr = imgFiles.map(async (element, index) => {
      const res = await timedGetText(fileUrl + '/download_base64/' + element.id)
      return {
        imgId: res.data.id,
        fullUrl: 'data:image/jpg;base64,' + res.data.dataBase64,
        bigUrl: 'data:image/jpg;base64,' + res.data.dataBase64,
        url: 'data:image/jpg;base64,' + res.data.dataBase64,
        fileType: calFileType(res.data.name),
        fileName: res.data.name
      }
    })
    Promise.all(tempFilesArr).then(res => {
      imgFilesInfo = res
      state.fileList = [...res, ...notImgFiles]
      loading.value = false
      empty.value = false
    })
  } else {
    if (!res.data || res.data.length === 0) {
      empty.value = true
    }
    state.fileList = [...imgFilesInfo, ...notImgFiles]
    loading.value = false
  }
}

const getAllFiles = url => {
  return new Promise((resolve, reject) => {
    var request = new XMLHttpRequest()
    request.open('GET', url)
    request.setRequestHeader('Authorization', userStore.token)
    request.onreadystatechange = function () {
      if (request.readyState !== 4) return
      if (request.status === 200) {
        resolve(JSON.parse(request.responseText))
      }
    }
    request.send()
  })
}

const timedGetText = url => {
  return new Promise((resolve, reject) => {
    var request = new XMLHttpRequest()
    request.open('GET', url)
    request.setRequestHeader('Authorization', userStore.token)
    request.onreadystatechange = function () {
      if (request.readyState !== 4) return
      if (request.status === 200) {
        resolve(JSON.parse(request.responseText))
      }
    }
    request.send()
  })
}

watch(
  () => state.fileList,
  val => {
    if (props.disabled) {
      hideUpload.value = true
      return
    }
    if (val.length > 0) {
      let ids = ''
      val.forEach(item => {
        if (item.imgId) {
          ids = ids + item.imgId + ','
        }
      })

      emit('update:bizId', ids)
      emit('success')
      if (props.validateField) {
        props.validateField()
      }
    } else {
      emit('update:bizId', '')
      if (props.validateField) {
        props.validateField()
      }
    }

    if (val.length >= props.limit) {
      hideUpload.value = true
    } else {
      hideUpload.value = false
    }
  },
  { deep: true }
)

const httpRequest = async request => {
  loading.value = true
  let params = new FormData()
  params.append('file', state.file)
  let result = await upload_file(params)
  if (result.succeed) {
    let file = state.file
    file.imgId = result.data
    file.fullUrl = URL.createObjectURL(file)
    file.bigUrl = URL.createObjectURL(file)
    file.url = URL.createObjectURL(file)
    file.fileType = calFileType(file.name)
    file.fileName = file.name
    state.fileList_local.push(file)
    state.fileList = JSON.parse(JSON.stringify(state.fileList_local))
    loading.value = false
  }
}

const getCrop = () => {
  // 获取截图的 base64 数据
  cropper.value.getCropData(data => {
    //  console.log(data);
  })
  // 获取截图的 blob 数据
  //console.log(cropper.value);
  cropper.value.getCropBlob(data => {
    let type = data.type.split('/')
    const files = new window.File([data], `img.${type[1]}`, {
      type: data.type
    })
    state.file = files
    // emit('closeAvatarDialog')
    fileUpload.value.submit()
    // 清空文件 否则会重复执行httpRequest方法
    fileUpload.value.clearFiles()
    showCropper.value = false
  })
}

const cancel = () => {
  options.img = ''
  showCropper.value = false
}

const openCropper = file => {
  var files = file

  hideUpload.value = true
  loading.value = true
  let status = 0
  if (props.allowUploadTypes.indexOf('mp4') != -1) {
    let url = URL.createObjectURL(file)
    var audioElement = new Audio(url)
    audioElement.addEventListener('loadedmetadata', function () {
      let playTime = audioElement.duration //playTime就是当前视频长度
      emit('videoInfos', {
        duration: playTime,
        type: file.type,
        size: changeSize(file.size)
      })
    })
  }

  if (props.allowUploadTypes.length > 0) {
    const fileType = file.name.replace(/.+\./, '')
    const result = ALL_TYPE.find(item => item == fileType)
    const isConformType = props.allowUploadTypes.indexOf(result) === -1
    if (isConformType) {
      ElMessage.error(`请上传${props.allowUploadTypes.join('，')}格式文件!`)
      hideUpload.value = false
      loading.value = false
      status = 0
    } else {
      status += 1
    }
  }

  const isConform = file.size / 1024 / 1024 > props.fileSize

  if (isConform) {
    ElMessage.error(`上传文件大小不能超过${props.fileSize}MB!`)
    hideUpload.value = false
    loading.value = false
    status = 0
  } else {
    status += 1
  }

  if (status == 2) {
    var reader = new FileReader()
    reader.onload = e => {
      let data
      if (typeof e.target.result === 'object') {
        // 把Array Buffer转化为blob 如果是base64不需要
        data = window.URL.createObjectURL(new Blob([e.target.result]))
      } else {
        data = e.target.result
      }
      options.img = data
    }
    // 转化为base64
    // reader.readAsDataURL(file)
    // 转化为blob
    reader.readAsArrayBuffer(files)
    showCropper.value = true
  } else {
    console.log(fileUpload.value)
    fileUpload.value.clearFiles()
  }
}

// 选择文件
const selectChange = file => {
  const { raw } = file
  openCropper(raw)
}

const calFileType = url => {
  const fileType = url.replace(/.+\./, '')
  const result = ALL_TYPE.find(item => item == fileType)
  if (IMG.indexOf(result) > -1) return 'img'
  if (EXCEL.indexOf(result) > -1) return 'excel'
  if (WORD.indexOf(result) > -1) return 'word'
  if (PPT.indexOf(result) > -1) return 'ppt'
  if (VIDEO.indexOf(result) > -1) return 'video'
  if (PDF.indexOf(result) > -1) return 'pdf'
  return result ? fileType : 'unknown'
}

const delFile = file => {
  state.fileList = state.fileList.filter(item => item.imgId != file.imgId)
}

const uploadSuccess = (res, file, fileListCom) => {
  console.log('success')
  loading.value = true
  if (res.succeed) {
    file.imgId = res.data
    file.fullUrl = file.url
    file.bigUrl = file.url
    file.url = file.url
    file.fileType = calFileType(file.name)
    file.fileName = file.name
    state.fileList = fileListCom
  } else {
    ElMessage.error(res.msg) // 后加的 因request.js未生效
  }
  loading.value = false
}

const viewImg = file => {
  showViewer.value = true
  selectImg.value = [file.bigUrl]
}

const closeViewer = () => {
  showViewer.value = false
}

onBeforeMount(() => {
  if (props.bizId && props.bizId !== '--') {
    init(userStore.fileUrl)
  } else {
    empty.value = true
    if (props.disabled) {
      hideUpload.value = true
    }
    loading.value = false
  }
})
</script>

<style lang="scss" scoped>
.file-type-icon {
  width: 48px;
  margin-left: 49px;
  margin-top: 40px;
  height: 50px;
}

.pub-upload {
  min-height: 164px;

  .hide {
    :deep(.el-upload--picture-card) {
      display: none;
    }
  }

  :deep(.el-upload-list__item:first-child) {
    margin-top: 0;
  }

  :deep(.el-upload-list--picture-card) {
    line-height: 0;

    .el-upload-list__item {
      margin: 8px;
    }
  }

  :deep(.el-upload--picture-card) {
    margin: 8px;
  }

  .empty-content {
    height: 164px;
    line-height: 164px;
    font-size: 13px;
    padding-left: 50%;
    position: relative;
    left: -27px;
    color: #333;
  }

  .file-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
    color: #999;
    padding: 0 10px;
    text-align: center;
  }
}
.crop-box {
  width: 100%;
  height: 550px;
}
.cropper-bottom {
  // background-color: rgb(192, 227, 255);
  height: 40px;
  text-align: center;
  line-height: 40px;
}
</style>
